package com.itmayiedu.controller;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.ui.Model;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;

import com.itmayiedu.exception.UserNotExistException;
import com.itmayiedu.exception.ValidatatorException;
import com.itmayiedu.response.ReturnFormat;

@RestControllerAdvice  //@RestControllerAdvice 等于@ControllerAdvice + @ResponseBody
//@ControllerAdvice //只负责处理异常
//@ControllerAdvice启动应用后，被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法，都会作用在 被 @RequestMapping 注解的方法上。
public class ControllerExceptionHandler {
	private static Logger log = LoggerFactory.getLogger(ControllerExceptionHandler.class);
	
	/**
     * 全局异常捕捉处理
     * @param ex
     * @return
     */
	@ExceptionHandler(UserNotExistException.class)
	//@ResponseBody
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public ModelAndView handleUserNotExistException(UserNotExistException ex){
		ModelAndView modelAndView = new ModelAndView();
		//把需要的信息放到异常中
		modelAndView.setViewName("404");
		//设置viewname 为error 可能会有问题，不要设置为error
		
		modelAndView.addObject("result", ex.getResult());
		modelAndView.addObject("reason", ex.getReason());
		
		log.error(modelAndView.toString());
		//System.out.println("123 test");
	
		return modelAndView;
		
	}
	
	/**
     * 全局异常捕捉处理
     * @param ex
     * @return
     */
	@ExceptionHandler(ValidatatorException.class)
	//@ResponseBody
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public ModelAndView handleValidatatorException(ValidatatorException ex){
		ModelAndView modelAndView = new ModelAndView();
		//把需要的信息放到异常中
		modelAndView.setViewName("500");
		//设置viewname 为error 可能会有问题，不要设置为error
		modelAndView.addObject("result", ex.getResult());
		modelAndView.addObject("reason", ex.getReason());
		
		log.error(modelAndView.toString());
		//System.out.println("123 test");
	
		return modelAndView;
		
	}

	/**
     * 应用到所有@RequestMapping注解方法，在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * 把值绑定到Model中，使全局@RequestMapping可以获取到该值
     * @param model
     * 
     * demo:
     * @RequestMapping("/home")
	 *	public String home(@ModelAttribute("author") String author) {
	 *	    System.out.println(author);
	 *	}
	 *  
	 *  or
	 *  @RequestMapping("/home")
	 *	public String home(ModelMap modelMap) {
	 *	    System.out.println(modelMap.get("author"));
	 *	}
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "Sam");
    }
    
    
    //运行时异常
    @ExceptionHandler(RuntimeException.class)  
    @ResponseBody  
    public String runtimeExceptionHandler(RuntimeException runtimeException) {  

        return ReturnFormat.retParam(1000, null);
    }  

    //空指针异常
    @ExceptionHandler(NullPointerException.class)  
    @ResponseBody  
    public String nullPointerExceptionHandler(NullPointerException ex) {  
        ex.printStackTrace();
        return ReturnFormat.retParam(1001, null);
    }   
    //类型转换异常
    @ExceptionHandler(ClassCastException.class)  
    @ResponseBody  
    public String classCastExceptionHandler(ClassCastException ex) {  
        ex.printStackTrace();
        return ReturnFormat.retParam(1002, null);  
    }  

    //IO异常
    @ExceptionHandler(IOException.class)  
    @ResponseBody  
    public String iOExceptionHandler(IOException ex) {  
        ex.printStackTrace();
        return ReturnFormat.retParam(1003, null); 
    }  
    //未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)  
    @ResponseBody  
    public String noSuchMethodExceptionHandler(NoSuchMethodException ex) {  
        ex.printStackTrace();
        return ReturnFormat.retParam(1004, null);
    }  

    //数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)  
    @ResponseBody  
    public String indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {  
        ex.printStackTrace();
        return ReturnFormat.retParam(1005, null);
    }
    //400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseBody
    public String requestNotReadable(HttpMessageNotReadableException ex){
        System.out.println("400..requestNotReadable");
        ex.printStackTrace();
        return ReturnFormat.retParam(400, null);
    }
    //400错误
    @ExceptionHandler({TypeMismatchException.class})
    @ResponseBody
    public String requestTypeMismatch(TypeMismatchException ex){
        System.out.println("400..TypeMismatchException");
        ex.printStackTrace();
        return ReturnFormat.retParam(400, null);
    }
    //400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseBody
    public String requestMissingServletRequest(MissingServletRequestParameterException ex){
        System.out.println("400..MissingServletRequest");
        ex.printStackTrace();
        return ReturnFormat.retParam(400, null);
    }
    //405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseBody
    public String request405(){
        System.out.println("405...");
        return ReturnFormat.retParam(405, null);
    }
    //406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    @ResponseBody
    public String request406(){
        System.out.println("404...");
        return ReturnFormat.retParam(406, null);
    }
    //500错误
    @ExceptionHandler({ConversionNotSupportedException.class,HttpMessageNotWritableException.class})
    @ResponseBody
    public String server500(RuntimeException runtimeException){
        System.out.println("500...");
        return ReturnFormat.retParam(406, null);
    }
}
